import { forwardRef, memo, useImperativeHandle, useState } from 'react'
import { Button, DatePicker, Form, Image, Input, InputNumber, Radio, Select, Switch, Upload, TreeSelect } from 'antd'
import { UploadOutlined } from '@ant-design/icons'
import dayjs from 'dayjs'
import type { Dayjs } from 'dayjs'
import type { ReactNode } from 'react'
import type { Elements, IBaseFormConfig, IBaseFormExp } from './typing'
import { ElementType } from './typing'

interface IProps {
  children?: ReactNode
  config: IBaseFormConfig
}

const BaseForm = forwardRef<IBaseFormExp, IProps>((props, ref) => {
  const {
    config: {
      elements: els, // 配置项
      layout, // Form 排版
      initialValues, // 初始
      formPorps // Form props
    }
  } = props
  const [form] = Form.useForm<any>() // 实例
  // 暴露
  useImperativeHandle<IBaseFormExp, IBaseFormExp>(
    ref,
    () => ({
      baseFormInstance: form // 暴露实例
    }),
    []
  )
  return (
    <Form
      form={form}
      layout={layout ?? 'inline'} // Form 排版
      initialValues={initialValues} // 初始
      labelCol={{ span: 8 }}
      wrapperCol={{ span: 16 }}
      {...formPorps} // Form props
    >
      {els.map((el: Elements) => {
        const {
          key,
          type, // 组件类型
          label, // 标题
          formItemProps // Form.Item props
        } = el
        switch (type) {
          case ElementType.BUTTON:
            return (
              <Form.Item key={key} noStyle={el.noStyle ?? true} {...formItemProps}>
                <Button type='primary' loading={el.loading} disabled={el.disabled} onClick={el.onClick} {...el.props}>
                  {label}
                </Button>
              </Form.Item>
            )
          case ElementType.INPUT:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <Input
                  placeholder='请输入...'
                  disabled={el.disabled}
                  onBlur={el.onBlur}
                  onChange={el.onChange}
                  {...el.props}
                />
              </Form.Item>
            )
          case ElementType.INPUTNUMBER:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <InputNumber
                  placeholder='请输入...'
                  min={el.min}
                  max={el.max}
                  addonAfter={el.addonAfter}
                  disabled={el.disabled}
                  onBlur={el.onBlur}
                  onChange={el.onChange}
                  {...el.props}
                />
              </Form.Item>
            )
          case ElementType.TEXTAREA:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <Input.TextArea
                  placeholder='请输入...'
                  disabled={el.disabled}
                  onBlur={el.onBlur}
                  onChange={el.onChange}
                  {...el.props}
                />
              </Form.Item>
            )
          case ElementType.SELECT:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <Select
                  placeholder='请选择...'
                  options={el.options}
                  allowClear={el.allowClear}
                  disabled={el.disabled}
                  onChange={el.onChange}
                  {...el.props}
                />
              </Form.Item>
            )
          case ElementType.TREESELECT:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <TreeSelect
                  placeholder='请选择...'
                  treeData={el.options}
                  allowClear={el.allowClear}
                  disabled={el.disabled}
                  onChange={el.onChange}
                  {...el.props}
                />
              </Form.Item>
            )

          case ElementType.RADIO:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <Radio.Group disabled={el.disabled} options={el.options} {...el.props} />
              </Form.Item>
            )
          case ElementType.SWITCH:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <Switch defaultChecked={el.defaultChecked} onChange={el.onChange} {...el.props} />
              </Form.Item>
            )
          case ElementType.DATEPICKER:
            return (
              <Form.Item key={key} label={label} name={el.field} rules={el.rules} {...formItemProps}>
                <DatePicker placeholder='请选择...' allowClear={el.allowClear} {...el.props} />
              </Form.Item>
            )
          case ElementType.RANGEPICKER:
            return (
              <Form.Item
                key={key}
                label={label}
                name={el.field}
                rules={el.rules}
                normalize={(values: [Dayjs, Dayjs] | null) => {
                  if (!values) return values
                  const [startTime, endTime] = values
                  return [dayjs(startTime).format('YYYY-MM-DD 00:00:00'), dayjs(endTime).format('YYYY-MM-DD 23:59:59')]
                }}
                getValueProps={(value: any) => {
                  if (typeof value === 'string') return { value: dayjs(value, 'YYYY-MM-DD HH:mm:ss') }
                  return {}
                }}
                {...formItemProps}
              >
                <DatePicker.RangePicker
                  placeholder={['请选择...', '请选择...']}
                  allowClear={el.allowClear}
                  {...el.props}
                />
              </Form.Item>
            )
          // 图片上传相关
          case ElementType.UPLOAD:
            const normFile = (e: any) => {
              if (Array.isArray(e)) return e
              return e?.fileList
            }
            /* 图片上传相关 */
            const [previewOpen, setPreviewOpen] = useState<boolean>(false)
            const [previewImage, setPreviewImage] = useState<string | null>(null)
            const getBase64 = (file: Blob) =>
              new Promise((resolve, reject) => {
                const reader = new FileReader()
                reader.readAsDataURL(file)
                reader.onload = () => resolve(reader.result)
                reader.onerror = error => reject(error)
              })
            const handlePreview = async (file: any) => {
              if (!file.url && !file.preview) {
                file.preview = await getBase64(file.originFileObj)
              }
              setPreviewImage(file.url || file.preview)
              setPreviewOpen(true)
            }
            return (
              <Form.Item
                key={key}
                label={label}
                name={el.field}
                valuePropName='fileList'
                getValueFromEvent={normFile}
                rules={el.rules}
                {...formItemProps}
              >
                {/* 文件上传及上传列表 */}
                <Upload
                  listType={el.listType}
                  accept={el.accept ?? (['text', undefined].includes(el.listType) ? undefined : 'image/*')}
                  maxCount={el.maxCount}
                  multiple={el.multiple}
                  beforeUpload={() => false}
                  onPreview={handlePreview}
                  onChange={el.onChange}
                  {...el.props}
                >
                  {el.children ??
                    (['text', 'picture', undefined].includes(el.listType) ? (
                      <Button type='primary' icon={<UploadOutlined />}>
                        点击上传
                      </Button>
                    ) : (
                      // el.listType === 'picture-card' | 'picture-circle'
                      <button type='button' style={{ border: 0, background: 'none', cursor: 'inherit' }}>
                        <UploadOutlined />
                        <div style={{ marginTop: '8px' }}>点击上传</div>
                      </button>
                    ))}
                </Upload>

                {/* 图片预览 */}
                {previewImage && (
                  <Image
                    wrapperStyle={{
                      display: 'none'
                    }}
                    preview={{
                      visible: previewOpen,
                      onVisibleChange: visible => setPreviewOpen(visible),
                      afterOpenChange: visible => !visible && setPreviewImage(null)
                    }}
                    src={previewImage}
                  />
                )}
              </Form.Item>
            )
          case ElementType.IMAGE:
            return (
              <Form.Item key={key} label={label} {...formItemProps}>
                {el.group ? (
                  <Image.PreviewGroup items={el.items}>
                    {el.items.length && <Image src={el.items[0]} {...el.props} />}
                  </Image.PreviewGroup>
                ) : (
                  <Image src={el.src} {...el.props} />
                )}
              </Form.Item>
            )
          case ElementType.CUSTOM:
            return (
              <Form.Item key={key} label={label} noStyle={el.noStyle} {...formItemProps}>
                {el.element}
              </Form.Item>
            )
          default:
            return <></>
        }
      })}
    </Form>
  )
})

export default memo(BaseForm)
